#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""测试 IRGroupNode 合并优化 Pass"""

import unittest
from mcpy.ir import IRModule, IRFunctionNode, IRClassNode, IRGroupNode
from mcpy.passes.group_merge import GroupMergePass
from mcpy.passes.base import PassContext
from unittest.mock import Mock


class TestGroupMergePass(unittest.TestCase):
    """测试 IRGroupNode 合并优化 Pass"""

    def setUp(self):
        """设置测试环境"""
        self.pass_instance = GroupMergePass()
        # 创建一个 mock 的 PassContext
        self.context = Mock(spec=PassContext)

    def test_no_group_nodes(self):
        """测试没有 IRGroupNode 的情况"""
        # 创建测试模块
        ir_module = IRModule(name="test_module")

        # 添加普通节点
        func1 = IRFunctionNode(name="func1", source_line=1)
        func2 = IRFunctionNode(name="func2", source_line=2)
        ir_module.add_node(func1)
        ir_module.add_node(func2)

        # 运行 Pass
        result = self.pass_instance.run(ir_module, self.context)

        # 验证结果
        self.assertEqual(len(result.nodes), 2)
        self.assertIs(result.nodes[0], func1)
        self.assertIs(result.nodes[1], func2)

    def test_single_group_node(self):
        """测试单个 IRGroupNode 的情况"""
        # 创建测试模块
        ir_module = IRModule(name="test_module")

        # 创建 IRGroupNode
        func1 = IRFunctionNode(name="func1", source_line=1)
        group1 = IRGroupNode(
            name="namespace_group1",
            source_line=1,
            nodes=[func1],
            tag="namespace",
            params={"name": "test::ns"},
        )

        ir_module.add_node(group1)

        # 运行 Pass
        result = self.pass_instance.run(ir_module, self.context)

        # 验证结果 - 单个节点不应该被修改
        self.assertEqual(len(result.nodes), 1)
        self.assertIs(result.nodes[0], group1)

    def test_merge_consecutive_same_groups(self):
        """测试合并连续的相同 IRGroupNode"""
        # 创建测试模块
        ir_module = IRModule(name="test_module")

        # 创建相同的 IRGroupNode
        func1 = IRFunctionNode(name="func1", source_line=1)
        func2 = IRFunctionNode(name="func2", source_line=2)
        func3 = IRFunctionNode(name="func3", source_line=3)

        group1 = IRGroupNode(
            name="namespace_group1",
            source_line=1,
            nodes=[func1],
            tag="namespace",
            params={"name": "test::ns"},
        )

        group2 = IRGroupNode(
            name="namespace_group2",
            source_line=2,
            nodes=[func2],
            tag="namespace",
            params={"name": "test::ns"},  # 相同的 tag 和 params
        )

        group3 = IRGroupNode(
            name="namespace_group3",
            source_line=3,
            nodes=[func3],
            tag="namespace",
            params={"name": "test::ns"},  # 相同的 tag 和 params
        )

        ir_module.add_node(group1)
        ir_module.add_node(group2)
        ir_module.add_node(group3)

        # 运行 Pass
        result = self.pass_instance.run(ir_module, self.context)

        # 验证结果 - 应该合并为一个节点
        self.assertEqual(len(result.nodes), 1)
        merged_group = result.nodes[0]
        assert isinstance(merged_group, IRGroupNode)
        self.assertEqual(merged_group.tag, "namespace")
        self.assertEqual(merged_group.params, {"name": "test::ns"})
        self.assertEqual(len(merged_group.nodes), 3)  # 包含所有三个函数

        # 验证节点顺序
        self.assertEqual(merged_group.nodes[0].name, "func1")
        self.assertEqual(merged_group.nodes[1].name, "func2")
        self.assertEqual(merged_group.nodes[2].name, "func3")

    def test_no_merge_different_tags(self):
        """测试不同 tag 的 IRGroupNode 不会被合并"""
        # 创建测试模块
        ir_module = IRModule(name="test_module")

        # 创建不同 tag 的 IRGroupNode
        func1 = IRFunctionNode(name="func1", source_line=1)
        func2 = IRFunctionNode(name="func2", source_line=2)

        group1 = IRGroupNode(
            name="namespace_group1",
            source_line=1,
            nodes=[func1],
            tag="namespace",
            params={"name": "test::ns"},
        )

        group2 = IRGroupNode(
            name="export_group1",
            source_line=2,
            nodes=[func2],
            tag="export",  # 不同的 tag
            params={"name": "test::ns"},
        )

        ir_module.add_node(group1)
        ir_module.add_node(group2)

        # 运行 Pass
        result = self.pass_instance.run(ir_module, self.context)

        # 验证结果 - 不应该合并
        self.assertEqual(len(result.nodes), 2)
        self.assertIs(result.nodes[0], group1)
        self.assertIs(result.nodes[1], group2)

    def test_no_merge_different_params(self):
        """测试不同 params 的 IRGroupNode 不会被合并"""
        # 创建测试模块
        ir_module = IRModule(name="test_module")

        # 创建不同 params 的 IRGroupNode
        func1 = IRFunctionNode(name="func1", source_line=1)
        func2 = IRFunctionNode(name="func2", source_line=2)

        group1 = IRGroupNode(
            name="namespace_group1",
            source_line=1,
            nodes=[func1],
            tag="namespace",
            params={"name": "test::ns1"},
        )

        group2 = IRGroupNode(
            name="namespace_group2",
            source_line=2,
            nodes=[func2],
            tag="namespace",
            params={"name": "test::ns2"},  # 不同的 params
        )

        ir_module.add_node(group1)
        ir_module.add_node(group2)

        # 运行 Pass
        result = self.pass_instance.run(ir_module, self.context)

        # 验证结果 - 不应该合并
        self.assertEqual(len(result.nodes), 2)
        self.assertIs(result.nodes[0], group1)
        self.assertIs(result.nodes[1], group2)

    def test_merge_with_interruption(self):
        """测试被其他节点中断的 IRGroupNode 不会被合并"""
        # 创建测试模块
        ir_module = IRModule(name="test_module")

        # 创建节点
        func1 = IRFunctionNode(name="func1", source_line=1)
        func2 = IRFunctionNode(name="func2", source_line=2)
        func3 = IRFunctionNode(name="func3", source_line=3)
        interruption = IRClassNode(name="InterruptClass", source_line=4)

        group1 = IRGroupNode(
            name="namespace_group1",
            source_line=1,
            nodes=[func1],
            tag="namespace",
            params={"name": "test::ns"},
        )

        group2 = IRGroupNode(
            name="namespace_group2",
            source_line=2,
            nodes=[func2],
            tag="namespace",
            params={"name": "test::ns"},
        )

        group3 = IRGroupNode(
            name="namespace_group3",
            source_line=5,
            nodes=[func3],
            tag="namespace",
            params={"name": "test::ns"},
        )

        ir_module.add_node(group1)
        ir_module.add_node(group2)
        ir_module.add_node(interruption)  # 中断节点
        ir_module.add_node(group3)

        # 运行 Pass
        result = self.pass_instance.run(ir_module, self.context)

        # 验证结果 - group1 和 group2 应该合并，group3 单独存在
        self.assertEqual(len(result.nodes), 3)

        # 第一个应该是合并后的 group
        merged_group = result.nodes[0]
        assert isinstance(merged_group, IRGroupNode)
        self.assertEqual(len(merged_group.nodes), 2)

        # 第二个应该是中断节点
        self.assertIs(result.nodes[1], interruption)

        # 第三个应该是 group3
        self.assertIs(result.nodes[2], group3)

    def test_empty_module(self):
        """测试空模块"""
        ir_module = IRModule(name="empty_module")

        # 运行 Pass
        result = self.pass_instance.run(ir_module, self.context)

        # 验证结果
        self.assertEqual(len(result.nodes), 0)
        self.assertIs(result, ir_module)
